Option Explicit On 
Option Strict On

Imports TreeCreeper01Interfaces

Friend Class cSpeciesAbundanceList

    Implements ISpeciesAbundanceList

    Private mTaxonomicDistanceProvider As ITaxonomicDistanceProvider
    Private pSpeciesCollection As Collection

    ' for creating initial base list

    Public Sub New(ByVal TaxonomicDistanceProvider As ITaxonomicDistanceProvider, Optional ByVal Abundances As IAbundanceCollection = Nothing)

        Dim SpeciesCollection As ITaxonomicSpeciesCollection
        Dim Index As Integer
        Dim OneSpecies As ITaxonomicSpecies
        Dim UniqueKey As String
        Dim Abundance As Double
        Dim Species As cSpeciesAbundance
        Dim TotalAbundance As Double
        Dim MaximumAbundance As Double

        mTaxonomicDistanceProvider = TaxonomicDistanceProvider

        pSpeciesCollection = New Collection

        SpeciesCollection = mTaxonomicDistanceProvider.AllSpecies

        'Normalise the abundances
        If Not IsNothing(Abundances) AndAlso Abundances.Count > 0 Then
            For Index = 1 To SpeciesCollection.Count
                OneSpecies = SpeciesCollection.TaxonomicSpeciesByIndexBaseOne(Index)
                UniqueKey = OneSpecies.UniqueKey
                Abundance = Abundances.AbundanceByUniqueKey(UniqueKey)
                TotalAbundance = TotalAbundance + Abundance
                If Abundance > MaximumAbundance Then
                    MaximumAbundance = Abundance
                End If
                Species = New cSpeciesAbundance(OneSpecies, Abundance)
                pSpeciesCollection.Add(Species, UniqueKey)
            Next
            For Index = 1 To pSpeciesCollection.Count
                Species = CType(pSpeciesCollection.Item(Index), cSpeciesAbundance)
                Species.NormaliseAbundance(MaximumAbundance)
            Next
        Else
            For Index = 1 To SpeciesCollection.Count
                OneSpecies = SpeciesCollection.TaxonomicSpeciesByIndexBaseOne(Index)
                UniqueKey = OneSpecies.UniqueKey
                Species = New cSpeciesAbundance(OneSpecies, 1)
                pSpeciesCollection.Add(Species, UniqueKey)
            Next
        End If


    End Sub

    ' for creating filtered lists
    Private Sub New(ByVal TaxonomicTree As ITaxonomicDistanceProvider, ByVal SpeciesCollection As Collection)
        mTaxonomicDistanceProvider = TaxonomicTree
        pSpeciesCollection = SpeciesCollection
    End Sub


    Public ReadOnly Property CountOfSpecies() As Integer Implements ISpeciesAbundanceList.CountOfSpecies
        Get
            Return pSpeciesCollection.Count
        End Get
    End Property


    Public ReadOnly Property SpeciesByIndexBaseOne(ByVal Index As Integer) As ISpeciesAbundance Implements ISpeciesAbundanceList.SpeciesByIndexBaseOne
        Get
            Dim Species As ISpeciesAbundance
            Species = CType(pSpeciesCollection.Item(Index), ISpeciesAbundance)
            Return Species
        End Get
    End Property


    Public ReadOnly Property TaxonomicDistanceProvider() As ITaxonomicDistanceProvider Implements ISpeciesAbundanceList.TaxonomicDistanceProvider
        Get
            Return mTaxonomicDistanceProvider
        End Get
    End Property

    Public Function NewSpeciesListByListFilter(ByVal ListFilter As IListFilter) As ISpeciesAbundanceList Implements ISpeciesAbundanceList.NewSpeciesListByListFilter

        Dim NewPotentialSpecies As ISpeciesAbundance
        Dim NewSpeciesCollection As Collection

        Dim ListFilterItemIndex As Integer
        Dim ListFilterItem As IListFilterItem
        Dim UniqueKeyToSeek As String
        Dim FilterValue As Double
        Dim RandomValue As Double

        NewSpeciesCollection = New Collection

        'Work over the filter objects which have been passed in, and select from self into a new cSpecies list.
        'Each filter item (selector) has a value, which if not = 0 or = 1 then will be used as a probability indicator and random test will be applied here - don't know why.

        For ListFilterItemIndex = 1 To ListFilter.Count
            ListFilterItem = ListFilter.ListFilterItemByIndexBaseOne(ListFilterItemIndex)
            UniqueKeyToSeek = ListFilterItem.UniqueKey

            NewPotentialSpecies = SpeciesByUniqueKey(UniqueKeyToSeek)

            If NewPotentialSpecies Is Nothing Then
                ' this is generally ok
            Else
                ' node is found and can be filtered
                FilterValue = ListFilterItem.Value

                If FilterValue = 0 Then
                    ' filter out
                    ' so do nothing
                ElseIf FilterValue >= 1 Then
                    ' filter in as propability greater than or equal to 100%
                    NewSpeciesCollection.Add(NewPotentialSpecies, NewPotentialSpecies.UniqueKey)
                Else
                    ' randomly filter in using given probability in 0..1 range
                    RandomValue = cRandomGenerator.NextRandomBetweenZeroAndOne
                    If RandomValue <= FilterValue Then
                        NewSpeciesCollection.Add(NewPotentialSpecies, NewPotentialSpecies.UniqueKey)
                    End If
                End If
            End If
        Next

        Return New cSpeciesAbundanceList(mTaxonomicDistanceProvider, NewSpeciesCollection)

    End Function


    Public ReadOnly Property SpeciesListAnalysis() As ISpeciesListAnalysis Implements ISpeciesAbundanceList.SpeciesListAnalysis
        Get
            Dim Analysis As ISpeciesListAnalysis
            Analysis = New cSpeciesListAnalysis(Me)
            Return Analysis
        End Get
    End Property


    Private Function SpeciesByUniqueKey(ByVal UniqueKeyToSeek As String) As ISpeciesAbundance
        Dim Species As ISpeciesAbundance
        Species = CType(pSpeciesCollection.Item(UniqueKeyToSeek), ISpeciesAbundance)
        Return Species
    End Function


End Class
